package com.wjk.cms.interceptor;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.wjk.cms.annotation.LoginRequired;
import com.wjk.cms.auth.AuthContext;
import com.wjk.cms.auth.AuthSubject;
import com.wjk.cms.exception.AuthenticationException;
import com.wjk.cms.pojo.User;
import com.wjk.cms.service.UserService;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

/**
 * 用户身份验证拦截器
 *
 * @author jinbin
 * @date 2018-07-08 20:41
 */
@Slf4j
public class AuthenticationInterceptor implements HandlerInterceptor {

    @Autowired
    private UserService userService;

    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
        // 如果不是映射到方法直接通过
        if (!(object instanceof HandlerMethod)) {
            return true;
        }

        HandlerMethod handlerMethod = (HandlerMethod) object;
        Class clazz = handlerMethod.getMethod().getDeclaringClass();
        Method method = handlerMethod.getMethod();
        LoginRequired loginRequiredAtClassLevel = AnnotationUtils.findAnnotation(clazz, LoginRequired.class);
        LoginRequired loginRequiredAtMethodLevel = AnnotationUtils.findAnnotation(method, LoginRequired.class);

        boolean loginRequired = false;
        if (loginRequiredAtMethodLevel != null && !loginRequiredAtMethodLevel.value()) {
            loginRequired = false;
        } else if (loginRequiredAtMethodLevel != null && loginRequiredAtMethodLevel.value()) {
            loginRequired = true;
        } else if (loginRequiredAtClassLevel != null && loginRequiredAtClassLevel.value()) {
            loginRequired = true;
        } else if (loginRequiredAtClassLevel == null || !loginRequiredAtClassLevel.value()) {
            loginRequired = false;
        }

        // 对于不需要用户登录的的，进行放行
        if (!loginRequired) {
            return true;
        }

        // 执行认证
        String token = httpServletRequest.getHeader("token"); // 从 http 请求头中取出 token
        if (token == null) {
            throw new AuthenticationException("无token，请重新登录");
        }
        // 获取 token 中的 user id
        Long userId;
        try {
            userId = Long.valueOf(JWT.decode(token).getAudience().get(0));
        } catch (Exception e) {
            throw new AuthenticationException("解析token失败，请重新登录", e);
        }
        log.info("userId:"+userId);
        User user = userService.findById(userId);
        if (user == null) {
            throw new AuthenticationException("用户不存在，请重新登录");
        }
        // 验证 token
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();
        try {
            jwtVerifier.verify(token);
        } catch (JWTVerificationException e) {
            e.printStackTrace();
            throw new AuthenticationException("验证token失败，请重新登录", e);
        }

        AuthContext.set(new AuthSubject(userId));
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
        try {
            AuthContext.clear();
        } catch (Throwable t) {
            log.error("清除Auth信息失败：" + t.getMessage(), t);
        }
    }

}
